using System;
using Firestarter.Test.Base;
using FireStarterModeller.BO;
using Habanero.Base;
using Habanero.BO;
using NUnit.Framework;

namespace FireStarterModeller.Test.BO
{
    [TestFixture]
    public class TestDMSortOrderPropMustBeOnClassRule
    {
        [SetUp]
        public void SetupTest()
        {
            //Runs every time that any testmethod is executed
            TestUtilsDomain.SetupTest();
            BORegistry.DataAccessor = new DataAccessorInMemory();
        }

        [TestFixtureSetUp]
        public void TestFixtureSetup()
        {
            //Code that is executed before any test is run in this class. If multiple tests
            // are executed then it will still only be called once.
            TestUtilsDomain.SetupFixture();
        }

        [TearDown]
        public void TearDownTest()
        {
            //runs every time any testmethod is complete
        }

        #region DMSortOrderPropMustBeOnClassRule

        [Test]
        public void Test_DMSortOrderPropMustBeOnClassRule()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = new DMRelationship();
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];
            SingleRelationship<DMClass> classRelationship = (SingleRelationship<DMClass>)dmRelationship.Relationships["ClassDM"];

            //---------------Assert Precondition----------------
            Assert.IsNotNull(dmRelationship);
            Assert.IsNotNull(sortOrderRelationship);
            Assert.IsNotNull(classRelationship);
            //---------------Execute Test ----------------------
            IBusinessObjectRule rule = new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship,
                sortOrderRelationship, classRelationship);
            //---------------Test Result -----------------------
            Assert.IsNotNull(rule);
            Assert.AreEqual("DMSortOrderPropMustBeOnClass", rule.Name);
            Assert.AreEqual(ErrorLevel.Warning, rule.ErrorLevel);

            StringAssert.Contains("The sort columns for ", rule.Message);
            StringAssert.Contains("'" + dmRelationship + "'", rule.Message);
            StringAssert.Contains("' must belong to the class.", rule.Message);
        }

        [Test]
        public void Test_CreateDMSortOrderPropMustBeOnClassRule_WhenBusinessObjectNull_ShouldRaiseError()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = new DMRelationship();
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];
            SingleRelationship<DMClass> classRelationship = (SingleRelationship<DMClass>)dmRelationship.Relationships["ClassDM"];

            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                new DMSortOrderPropMustBeOnRelatedClassRule(null, sortOrderRelationship, classRelationship);
                Assert.Fail("expected ArgumentNullException");
            }
            //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("businessObject", ex.ParamName);
            }
        }

        [Test]
        public void Test_CreateDMSortOrderPropMustBeOnClassRule_NullSortOrderRelationship_ShouldRaiseError()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = new DMRelationship();
            SingleRelationship<DMClass> classRelationship = (SingleRelationship<DMClass>)dmRelationship.Relationships["ClassDM"];

            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship, null, classRelationship);
                Assert.Fail("expected ArgumentNullException");
            }
            //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("sortOrderRelationship", ex.ParamName);
            }
        }

        [Test]
        public void Test_CreateDMSortOrderPropMustBeOnClassRule_NullClassRelationship_ShouldRaiseError()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = new DMRelationship();
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];

            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship, sortOrderRelationship, null);
                Assert.Fail("expected ArgumentNullException");
            }
            //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("dmClassRelationship", ex.ParamName);
            }
        }

        [Test]
        public void Test_IsValid_True_WhenNoPropsForDMSortOrder()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = new DMRelationship();
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];
            SingleRelationship<DMClass> classRelationship = (SingleRelationship<DMClass>)dmRelationship.Relationships["ClassDM"];
            IBusinessObjectRule rule = new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship,
                    sortOrderRelationship, classRelationship);
            //---------------Assert Precondition----------------
            DMSortOrder dmSortOrder = sortOrderRelationship.GetRelatedObject();
            Assert.AreEqual(0, dmSortOrder.DMSortProperties.Count);
            //---------------Execute Test ----------------------
            bool isValid = rule.IsValid(dmRelationship);
            //---------------Test Result -----------------------
            Assert.IsTrue(isValid);
        }

        [Test]
        public void Test_IsValid_True_WhenNoDMSortOrderSet()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = new DMRelationship();
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];
            SingleRelationship<DMClass> classRelationship = (SingleRelationship<DMClass>)dmRelationship.ReverseRelationship.Relationships["ClassDM"];
            dmRelationship.DMSortOrder = null;
            IBusinessObjectRule rule = new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship,
                    sortOrderRelationship, classRelationship);
            //---------------Assert Precondition----------------
            Assert.IsNull(dmRelationship.DMSortOrder);
            //---------------Execute Test ----------------------
            bool isValid = rule.IsValid(dmRelationship);
            //---------------Test Result -----------------------
            Assert.IsTrue(isValid);
        }

        [Test]
        public void Test_IsValid_True_NoRelatedClass()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = new DMRelationship();
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];
            SingleRelationship<DMClass> classRelationship = (SingleRelationship<DMClass>)dmRelationship.ReverseRelationship.Relationships["ClassDM"];
            DMSortOrder dmSortOrder = dmRelationship.DMSortOrder;
            DMSortProperty dmSortProperty = dmSortOrder.DMSortProperties.CreateBusinessObject();
            dmSortProperty.PropertyName = TestUtilsShared.GetRandomString();
            IBusinessObjectRule rule = new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship,
                    sortOrderRelationship, classRelationship);
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, dmSortOrder.DMSortProperties.Count);
            Assert.IsNull(dmRelationship.RelatedClass);
            //---------------Execute Test ----------------------
            bool isValid = rule.IsValid(dmRelationship);
            //---------------Test Result -----------------------
            Assert.IsTrue(isValid);
        }

        [Test]
        public void Test_IsValid_False_WhenPropDoesNotExists()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = TestUtilsShared.CreateUnsavedValidRelationshipInfo();
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];
            dmRelationship.RelatedClass = new DMClass();
            DMSortOrder dmSortOrder = dmRelationship.DMSortOrder;
            DMSortProperty dmSortProperty = dmSortOrder.DMSortProperties.CreateBusinessObject();
            dmSortProperty.PropertyName = TestUtilsShared.GetRandomString();
            SingleRelationship<DMClass> classRelationship = (SingleRelationship<DMClass>)dmRelationship.ReverseRelationship.Relationships["ClassDM"];
            IBusinessObjectRule rule = new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship,
                    sortOrderRelationship, classRelationship);
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, dmSortOrder.DMSortProperties.Count);
            Assert.AreEqual(0, dmRelationship.RelatedClass.Properties.Count);
            //---------------Execute Test ----------------------
            bool isValid = rule.IsValid(dmRelationship);
            //---------------Test Result -----------------------
            Assert.IsFalse(isValid);
            TestUtilsShared.AssertStringNotEmpty(rule.Message, "rule.Message");
        }

        [Test]
        public void Test_IsValid_True_WhenPropsExists()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = TestUtilsShared.CreateUnsavedValidRelationshipInfo();
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];
            DMProperty property = TestUtilsShared.CreateUnsavedValidDMProperty();
            dmRelationship.RelatedClass = property.Class;
            DMSortOrder dmSortOrder = dmRelationship.DMSortOrder;
            DMSortProperty dmSortProperty = dmSortOrder.DMSortProperties.CreateBusinessObject();
            dmSortProperty.PropertyName = property.PropertyName;
            SingleRelationship<DMClass> classRelationship = (SingleRelationship<DMClass>)dmRelationship.ReverseRelationship.Relationships["ClassDM"];
            IBusinessObjectRule rule = new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship,
                    sortOrderRelationship, classRelationship);
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, dmSortOrder.DMSortProperties.Count);
            Assert.AreEqual(1, dmRelationship.RelatedClass.Properties.Count);
            Assert.AreEqual(dmRelationship.RelatedClass.Properties[0].PropertyName, dmRelationship.DMSortOrder.DMSortProperties[0].PropertyName);
            //---------------Execute Test ----------------------
            bool isValid = rule.IsValid(dmRelationship);
            //---------------Test Result -----------------------
            Assert.IsTrue(isValid);
        }

        [Test]
        public void Test_IsValid_True_WhenTwoPropsBothExist()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = TestUtilsShared.CreateUnsavedValidRelationshipInfo();
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];
            DMProperty property1 = TestUtilsShared.CreateUnsavedValidDMProperty();
            DMProperty property2 = TestUtilsShared.CreateUnsavedValidDMProperty(property1.Class);
            dmRelationship.RelatedClass = property1.Class;
            DMSortOrder dmSortOrder = dmRelationship.DMSortOrder;
            DMSortProperty dmSortProperty1 = dmSortOrder.DMSortProperties.CreateBusinessObject();
            dmSortProperty1.PropertyName = property1.PropertyName; 
            DMSortProperty dmSortProperty2 = dmSortOrder.DMSortProperties.CreateBusinessObject();
            dmSortProperty2.PropertyName = property2.PropertyName;
            SingleRelationship<DMClass> classRelationship = (SingleRelationship<DMClass>)dmRelationship.ReverseRelationship.Relationships["ClassDM"];
            IBusinessObjectRule rule = new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship,
                    sortOrderRelationship, classRelationship);
            //---------------Assert Precondition----------------
            Assert.AreEqual(2, dmSortOrder.DMSortProperties.Count);
            Assert.AreEqual(2, dmRelationship.RelatedClass.Properties.Count);
            //---------------Execute Test ----------------------
            bool isValid = rule.IsValid(dmRelationship);
            //---------------Test Result -----------------------
            Assert.IsTrue(isValid);
        }

        [Test]
        public void Test_IsValid_False_WhenTwoPropsSecondOneNotExist()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = TestUtilsShared.CreateUnsavedValidRelationshipInfo();
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];
            DMProperty property1 = TestUtilsShared.CreateUnsavedValidDMProperty();
            TestUtilsShared.CreateUnsavedValidDMProperty(property1.Class);
            dmRelationship.RelatedClass = property1.Class;
            DMSortOrder dmSortOrder = dmRelationship.DMSortOrder;
            DMSortProperty dmSortProperty1 = dmSortOrder.DMSortProperties.CreateBusinessObject();
            dmSortProperty1.PropertyName = property1.PropertyName; 
            DMSortProperty dmSortProperty2 = dmSortOrder.DMSortProperties.CreateBusinessObject();
            dmSortProperty2.PropertyName =TestUtilsShared.GetRandomString();
            SingleRelationship<DMClass> classRelationship = (SingleRelationship<DMClass>)dmRelationship.ReverseRelationship.Relationships["ClassDM"];
            IBusinessObjectRule rule = new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship,
                    sortOrderRelationship, classRelationship);
            //---------------Assert Precondition----------------
            Assert.AreEqual(2, dmSortOrder.DMSortProperties.Count);
            Assert.AreEqual(2, dmRelationship.RelatedClass.Properties.Count);
            //---------------Execute Test ----------------------
            bool isValid = rule.IsValid(dmRelationship);
            //---------------Test Result -----------------------
            Assert.IsFalse(isValid);
            TestUtilsShared.AssertStringNotEmpty(rule.Message, "rule.Message");
        }

        [Test]
        public void Test_IsValid_True_WhenPropsExistOnSuperClass()
        {
            //---------------Set up test pack-------------------
            DMRelationship dmRelationship = TestUtilsShared.CreateUnsavedValidRelationshipInfo();
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];
            DMProperty property = TestUtilsShared.CreateUnsavedValidDMProperty();
            IDMClass dmClass = property.Class;
            dmRelationship.RelatedClass = dmClass;
            DMClass superClass = new DMClass();
            DMProperty superclassProperty = TestUtilsShared.CreateUnsavedValidDMProperty(superClass);
            dmClass.InheritanceSuperClassRelationship = new DMInheritanceRelationship();
            dmClass.InheritanceSuperClassRelationship.SuperClass = superClass;
            DMSortOrder dmSortOrder = dmRelationship.DMSortOrder;
            DMSortProperty dmSortProperty = dmSortOrder.DMSortProperties.CreateBusinessObject();
            dmSortProperty.PropertyName = superclassProperty.PropertyName;
            SingleRelationship<DMClass> classRelationship = (SingleRelationship<DMClass>)dmRelationship.ReverseRelationship.Relationships["ClassDM"];
            IBusinessObjectRule rule = new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship,
                    sortOrderRelationship, classRelationship);
            //---------------Assert Precondition----------------
            Assert.AreEqual(1, dmSortOrder.DMSortProperties.Count);
            Assert.AreEqual(1, dmRelationship.RelatedClass.Properties.Count);
            //---------------Execute Test ----------------------
            bool isValid = rule.IsValid(dmRelationship);
            //---------------Test Result -----------------------
            Assert.IsTrue(isValid);
        }

        [Test]
        public void Test_IsValid_True_When_PropIsOnSingleRelationship()
        {
            //---------------Set up test pack-------------------
            DMProperty dmClass1Prop = TestUtilsShared.CreateUnsavedValidDMProperty();
            DMClass dmClass1 = (DMClass)dmClass1Prop.Class;        //Invoice
            DMProperty dmClass1Prop2 = TestUtilsShared.CreateUnsavedValidDMProperty(dmClass1);
            DMClass dmClass2 = CreateClassWithOneProp(dmClass1.Solution);    //InvoiceLine 
            DMRelationship dmRelationship = dmClass1.OwnerRelationships.CreateBusinessObject();
            dmRelationship.RelationshipName = TestUtilsShared.GetRandomString();
            dmRelationship.Cardinality = Cardinality.Multiple;
            dmRelationship.RelatedClass = dmClass2;
            string reverseRelationshipName = TestUtilsShared.GetRandomString();
            dmRelationship.ReverseRelationshipName = reverseRelationshipName;
            DMSortOrder dmSortOrder = dmRelationship.DMSortOrder;
            DMSortProperty dmSortProperty = dmSortOrder.DMSortProperties.CreateBusinessObject();
            dmSortProperty.SortOrderPropertyName = dmRelationship.ReverseRelationshipName + "." + dmClass1Prop2.PropertyName;
            SingleRelationship<DMSortOrder> sortOrderRelationship = (SingleRelationship<DMSortOrder>)dmRelationship.Relationships["DMSortOrder"];
            SingleRelationship<DMClass> reverseSingleRelationship = (SingleRelationship<DMClass>)dmRelationship.ReverseRelationship.Relationships["ClassDM"];
            IBusinessObjectRule rule = new DMSortOrderPropMustBeOnRelatedClassRule(dmRelationship, sortOrderRelationship, reverseSingleRelationship);
            //---------------Assert Precondition----------------
            Assert.IsTrue(dmSortProperty.SortOrderPropertyName.Contains("."));
            //---------------Execute Test ----------------------
            bool isValid = rule.IsValid(dmRelationship);
            //---------------Test Result -----------------------
             Assert.IsTrue(isValid);
        }

        private DMClass CreateClassWithOneProp(IDMSolution dmSolution)
        {
            DMClass relatedClass = TestUtilsShared.CreateUnsavedValidDMClass(dmSolution);
            TestUtilsShared.CreateUnsavedValidDMProperty(relatedClass);
            return relatedClass;
        }

        #endregion
    }


}